%{
#include <string.h>
#include <stdlib.h>
#include "util.h"
#include "myutil.h"
#include "y.tab.h"
#include "errormsg.h"

int charPos=1;
int cmlevel=0;

int yywrap(void)
{
 charPos=1;
 return 1;
}

void adjust(void)
{
 EM_tokPos=charPos;
 yylval.pos=charPos;
 charPos+=yyleng;
}

char* cachedstr;
void init_cache(){ cachedstr = (char*)checked_malloc(1); cachedstr[0] = '\0'; }

void free_cache(){
	if(cachedstr)
		free(cachedstr);
}

void append(char* str){
	if(str == NULL)
		return;
	if(cachedstr){
		int len = strlen(cachedstr) + strlen(str);
		char* _t = (char*)checked_malloc(len + 1);
		strcpy(_t, cachedstr);
		strcpy(_t + strlen(cachedstr), str);
		_t[strlen(_t)] = '\0';
		free(cachedstr);
		cachedstr = _t;
	}else{
		init_cache();
		append(str);
	}
}

void append_ch(char ch){
	if(cachedstr){
		int len = strlen(cachedstr) + 1;
		char* _t = (char*)checked_malloc(len + 1);
		strcpy(_t, cachedstr);
		_t[strlen(_t)] = ch;
		_t[strlen(_t)] = '\0';
		free(cachedstr);
		cachedstr = _t;
	}else{
		init_cache();
		append_ch(ch);
	}
}
%}

%x COMMENT INSTRING INLSTRING

DIGIT		[0-9]
LINESPLIT	(\n|\r|\n\r|\r\n)
LETTER		[a-zA-Z]
WHITESPACE	(\t|" ")

IDER		({LETTER}+({LETTER}|{DIGIT}|"_")*)
INTLIT		({DIGIT}+)

%%
<INITIAL>\"		{adjust(); BEGIN INSTRING; init_cache(); continue;}	
<INITIAL>"/*"	{adjust(); BEGIN COMMENT; cmlevel = 1; continue;}

<INITIAL>"*/"	{adjust(); EM_error(EM_tokPos, "mismatched comments");}	
<INITIAL>{WHITESPACE}	{adjust(); continue;}
<INITIAL>{LINESPLIT}	{adjust(); EM_newline(); continue;}

<INITIAL>","	{adjust(); return COMMA;}
<INITIAL>":"	{adjust(); return COLON;}
<INITIAL>";"	{adjust(); return SEMICOLON;}
<INITIAL>"("	{adjust(); return LPAREN;}
<INITIAL>")"	{adjust(); return RPAREN;}
<INITIAL>"["	{adjust(); return LBRACK;}
<INITIAL>"]"	{adjust(); return RBRACK;}
<INITIAL>"{"	{adjust(); return LBRACE;}
<INITIAL>"}"	{adjust(); return RBRACE;}
<INITIAL>"."	{adjust(); return DOT;}
<INITIAL>"+"	{adjust(); return PLUS;}
<INITIAL>"-"	{adjust(); return MINUS;}
<INITIAL>"*"	{adjust(); return TIMES;}
<INITIAL>"/"	{adjust(); return DIVIDE;}
<INITIAL>"="	{adjust(); return EQ;}
<INITIAL>"<>"	{adjust(); return NEQ;}
<INITIAL>"<"	{adjust(); return LT;}
<INITIAL>"<="	{adjust(); return LE;}
<INITIAL>">"	{adjust(); return GT;}
<INITIAL>">="	{adjust(); return GE;}
<INITIAL>"&"	{adjust(); return AND;}
<INITIAL>"|"	{adjust(); return OR;}
<INITIAL>":="	{adjust(); return ASSIGN;}

<INITIAL>"if"		{adjust(); return IF;}
<INITIAL>"then"		{adjust(); return THEN;}
<INITIAL>"else"		{adjust(); return ELSE;}
<INITIAL>"while"	{adjust(); return WHILE;}
<INITIAL>"for"		{adjust(); return FOR;}
<INITIAL>"to"		{adjust(); return TO;}
<INITIAL>"do"		{adjust(); return DO;}
<INITIAL>"let"		{adjust(); return LET;}
<INITIAL>"in"		{adjust(); return IN;}
<INITIAL>"array"	{adjust(); return ARRAY;}
<INITIAL>"end"		{adjust(); return END;}
<INITIAL>"of"		{adjust(); return OF;}
<INITIAL>"break"	{adjust(); return BREAK;}
<INITIAL>"nil"		{adjust(); return NIL;}
<INITIAL>"function"	{adjust(); return FUNCTION;}
<INITIAL>"var"		{adjust(); return VAR;}
<INITIAL>"type"		{adjust(); return TYPE;}

<INITIAL>{INTLIT}	{adjust(); yylval.ival = atoi(yytext); return INT;}
<INITIAL>{IDER}		{adjust(); yylval.sval = String(yytext); return ID;}

<INITIAL>.		{adjust(); EM_error(EM_tokPos,"illegal token");}


<INSTRING>\"	{adjust(); BEGIN INITIAL; yylval.sval = String(cachedstr); free_cache(); return STRING;}
<INSTRING>\\	{adjust(); BEGIN INLSTRING; continue;}
<INSTRING>{LINESPLIT}	{adjust(); EM_error(EM_tokPos,"illegal line change");}

<INSTRING>[^\n\t\"\\]+	{adjust(); append(yytext); continue;}
<INSTRING>\\n	{adjust(); append(yytext); continue;}
<INSTRING>\\t	{adjust(); append(yytext); continue;}
<INSTRING>\\\"	{adjust(); append(yytext); continue;}
<INSTRING>\\\\	{adjust(); append(yytext); continue;}

<INSTRING>\\{DIGIT}{DIGIT}{DIGIT}	{
	int temp = atoi(yytext+1); 
	adjust(); 	
	if(temp <= 255){
		char ch = (char)temp;
		append_ch(ch);
		continue;
	}else{
		EM_error(EM_tokPos,"illegal char");
	}
}
<INSTRING><<EOF>>	{adjust(); EM_error(EM_tokPos, "Mismatch string"); yyterminate();}


<INLSTRING>{WHITESPACE}	{adjust(); continue;}
<INLSTRING>{LINESPLIT}	{adjust(); continue;}
<INLSTRING>\\	{adjust(); BEGIN INSTRING;}
<INLSTRING>\"	{adjust(); EM_error(EM_tokPos, "Mismatch quotes");}
<INLSTRING>.	{adjust(); continue;}
<INLSTRING><<EOF>>	{adjust(); EM_error(EM_tokPos, "Mismatch lined-string"); yyterminate();}


<COMMENT>"/*"	{adjust(); cmlevel+=1; continue;}
<COMMENT>"*/"	{adjust(); cmlevel-=1; if(cmlevel == 0) BEGIN INITIAL; continue;}
<COMMENT>.		{adjust(); continue;}
<COMMENT><<EOF>>	{adjust(); EM_error(EM_tokPos, "Mismatch comment"); yyterminate();}
%%
